LowMemoryKiller机制
Android的LowMemoryKiller(lmk)机制是一种内存回收机制,它根据当前系统的内存阈值以及进程的优先级来决定杀掉哪些进程。LowMemoryKiller会周期性的检查当前系统的可用内存,当系统剩余的可用内存较低时,便会触发进程杀掉进程的策略。它根据不同的内存阈值来决定杀掉相应优先级的进程。
Android的LowMemoryKiller机制是基于Linux的OOM Killer机制修改而来,在KK版本中,LMK机制和策略都是在内核空间驱动中实现的,在L版本中LowMemeoryKiller做了一些调整改动,但总体的思想还是一样的。
Kernel层的实现
1 | // kernel/drivers/staging/android/lowmemorykiller.c |
在lowmemorykiller中定义了两个数组分别是lowmem_infree和lowmem_adj,它们分别是用来描述当前系统的低内存阈值以及低内存阈值对应的进程优先级,lmk正是基于这个优先级来决定是否杀掉当前进程。
1 | static int __init lowmem_init(void) |
lmk将自己的lowmem_shrink方法诸恶到系统的内存检测模块中,作用就是在内存不足的时候可以被回调,register_shrinker函数是一属于另一个内存管理模块的函数。
1 | //内存检测模块检测到内存不足时调用,在这个方法里面会去查找低优先级的进程 |
lowmem_shrink是lmk的核心处理方法,它的逻辑比较简单,首先通过global_page_state得到当前系统可用的空闲内存大小,随后根据该空闲内存的大小找到相应的内存阈值对应的进程优先级并将其赋值给selected_oom_adj,低于该优先级的进程都有可能被lmk杀掉。for_each_process遍历进程列表,然后找出进程优先级最低的进程通过fore_sig选择杀死进程。
应用恢复机制
Android应用的恢复是通过AMS来进行的。那么AMS恢复的过程是如何的呢?AMS是怎么知道应用被杀掉的?
LowMemoryKiller杀死应用后并不会通知应用层,也不通知AMS,但是我们知道AMS和应用端的通信是基于Binder机制的,别忘了Binder是由卟告功能的,Binder Client通过linkToDeath注册接收该卟告。当Binder Server端死亡后会通过它来告知客户端。这里的Binder Server就是IApplicationThread,这个对象是在ActivityThread中创建的,用于AMS和客户端进行通信的,AMS就是通过它来告诉Activity执行一系列的回调方法。
1 | //应用创建完application后attach IApplicationThread 到AMS |
在应用创建后就AMS通过attachApplication调用attachApplicationLocked来注册Binder服务的卟告回调。它是一个AppDeathRecipient继承自IBinder.DeathRecipient,当服务端也就是应用端被杀掉后,会通过binderDied来通知AMS,这时候AMS通过appDiedLocked方法来处理应用被杀的逻辑。我们看看AMS这时候是如何处理的。
1 | //app被后台杀死后会通过此方法通知AMS ,这是由binder机制保证的 |
在appDiedLocked中进一步通过handleAppDiedLocked来处理。
1 | private final void handleAppDiedLocked(ProcessRecord app, |
handleAppDiedLocked主要负责以下事情:
- 负责清理一些Providers,receivers,service之类的信息
- 从活动的Activity列表移除该应用的Activities
- 通过resumeTopActivitiesLocked重建进程
1 | private final void cleanUpApplicationRecordLocked(ProcessRecord app, |
cleanUpApplicationRecordLocked负责清理应用的service,provider以及receiver的信息,并根据需要重启该进程。
1 | boolean handleAppDiedLocked(ProcessRecord app) { |
removeHistoryRecordsForAppLocked首先从mLRUActivities,mStoppingActivities,mGoingToSleepActivities等多个列表中移除app相关的activity,随后遍历ActivityStack找到和app相关的activity,根据不同的情况标记activity是否应该从历史列表中移除该activity,如果需要的话就调用removeActivityFromHistoryLocked,如果不需要就将r.app置为null。这样在AMS启动activity时就知道该应用的进程需要重建了。
1 | final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) { |
r.app被置位null后,AMS会去重建该activity对应的进程。